import uvm_pkg::*;
`include "uvm_macros.svh"

class spt_packet extends uvm_sequence_item;
	`protect128
	rand bit[15:0] header;
	rand bit[15:0] payload[$];
	rand bit[15:0] tailer;

	rand bit[15:0] pkt_data[];
	rand int 	   pkt_len;

	rand bit 	   head_err;
	rand bit 	   tailer_err;
	rand bit[1:0]  err_type;//00:normal; 01:tail_err; 10:head_err; 11:head_err&tail_err
	rand int	   payload_mode;//0:glitch; 1:short; 2:normal; 3:long; 4:short or normal or long
	
	`uvm_object_utils_begin(spt_packet)
		`uvm_field_int(header, UVM_ALL_ON)
		`uvm_field_queue_int(payload, UVM_ALL_ON)
		`uvm_field_int(tailer, UVM_ALL_ON)
		`uvm_field_array_int(pkt_data, UVM_ALL_ON)
		`uvm_field_int(pkt_len, UVM_ALL_ON)
		`uvm_field_int(head_err, UVM_ALL_ON | UVM_NOCOMPARE)
		`uvm_field_int(tailer_err, UVM_ALL_ON | UVM_NOCOMPARE)
		`uvm_field_int(err_type, UVM_ALL_ON | UVM_NOCOMPARE)
		`uvm_field_int(payload_mode, UVM_ALL_ON | UVM_NOCOMPARE)
	`uvm_object_utils_end
	
	constraint payload_mode_cons{payload_mode inside {[0:4]};}
	
	constraint err_type_cons{err_type inside {[0:3]};}
	
	constraint pkt_len_cons{
		pkt_len > 0;
		if(payload_mode == 0){ //glitch packet
			pkt_len <= 2;
		}
		else if(payload_mode == 1){ //short packet
			pkt_len > 2;
			pkt_len < 22;
		}
		else if(payload_mode == 2){ //normal packet
			pkt_len >= 22;
			pkt_len <= 602;
		}
		else if(payload_mode == 3){ //long packet
			pkt_len > 602;
			pkt_len < 1000;
		}
		else if(payload_mode == 4){ //shor or normal or long
			pkt_len > 2;
			pkt_len < 1000;
		}
	}
	
	constraint head_err_cons{
		if(err_type[1] == 1)
			head_err == 1'b1;
		else
			head_err == 1'b0;
	}
	
	constraint tailer_err_cons{
		if(err_type[0] == 1)
			tailer_err == 1'b1;
		else
			tailer_err == 1'b0;
	}
	
	constraint header_cons{
		if(head_err)
			header != 16'h55D5;
		else
			header == 16'h55D5;
	}
	
	constraint payload_cons{
		solve pkt_len before payload;
		if(pkt_len <= 2)
			payload.size == 0;
		else
			payload.size == pkt_len - 2;
	}
	
	function bit[15:0] tailer_calc(bit[15:0] payload[]);
		bit[16:0] sum_17;
		bit[15:0] sum_16;
		sum_17 = 0;
		sum_16 = 0;
		
		foreach(payload[i]) begin
			sum_17 = payload[i] + sum_16;
			sum_16 = sum_17[16] + sum_17[15:0];
			if(sum_16 == 16'hFFFF)begin
				tailer_calc = 16'hFFFF;
			end
			else begin
				tailer_calc = ~sum_16;
			end
		end
	endfunction: tailer_calc
	
	function new(string name = "spt_packet");
		super.new(name);
	endfunction: new
	
	function void do_pack(uvm_packer packer);
		bit[15:0] tailer_result;
		
		super.do_pack(packer);
		
		pkt_data = new[pkt_len];
		pkt_data[0] = header;
		tailer_result = tailer_calc(this.payload);
		if(tailer_err)
			randomize(tailer)with{tailer != tailer_result;};
		else
			tailer = tailer_result;
		pkt_data[pkt_len - 1] = tailer;
		foreach(payload[i])begin
			pkt_data[i+1] = payload[i];
		end
	endfunction: do_pack
	
	function void do_unpack(uvm_packer packer);
		super.do_unpack(packer);
	endfunction:do_unpack
	
	function void pre_randomize();
	endfunction: pre_randomize
	
	function void post_randomize();
	endfunction: post_randomize
	`endprotect128	
endclass: spt_packet
